/**********************************************************************
 *File		:	mo_mcu.c
 *Time		:	2022/6/3
 *Author		:	Bryan He（贺璧）
 *Discreption:
 *
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "mo_config.h"

#ifdef WINDOWS_DEMO_EN
#include <Windows.h>
#endif

static mo_u32 moTick = 0;
#define mo_tick moTick
/*****The os_tick_inc should be invoked in timer IRQ
 * function*********************/
void mo_tick_inc(void) { mo_tick++; }

void mo_reset_mcu(void) {
    /*@TODO: here to reset the MCU you own***/

#ifdef OS_FOR_STM32
#define FORCE_SYSTEMP_RESET() NVIC_SystemReset() /**/
#elif defined(OS_FOR_STM8)
#define FORCE_SYSTEMP_RESET() WWDG_SWReset() /**/
#elif defined(WINDOWS_DEMO_EN)
#define FORCE_SYSTEMP_RESET()
#elif defined(MO_CH58x)
#define FORCE_SYSTEMP_RESET() SYS_ResetExecute()
#else

#endif
}

/*@TODO: place mo_tick_timer_irq_handle() into the timer interrupt service of
the MCU you own *void mo_tick_timer_irq_handle(void){	mo_tick_inc();
}*/
/***********************************************/
#ifdef MO_CHV32V30x

void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

/*********************************************************************
 * @fn      Interrupt_VTF_Init
 *
 * @brief   Initializes VTF.
 *
 * @return  none
 */
void Interrupt_VTF_Init(void) {
    NVIC_EnableIRQ(SysTicK_IRQn);
    SetVTFIRQ((mo_u32)SysTick_Handler, SysTicK_IRQn, 0, ENABLE);
}
/*********************************************************************
 * @fn      SysTick_Handler
 *
 * @brief   This function handles SysTick exception.
 *
 * @return  none
 */
void SysTick_Handler(void) {
    mo_tick_inc();
    // SysTick->CTLR=0;
    SysTick->SR = 0;
    // printf("delta time:%d \n",time);
    SysTick->CNT = 0;
}
#endif

#ifdef MO_CH58x
/*********************************************************************
 * @fn      TMR0_IRQHandler
 *
 * @brief   TMR0中断函数
 *
 * @return  none
 */
__INTERRUPT
__HIGH_CODE
void TMR0_IRQHandler(void) {  // TMR0 定时中断

    if (TMR0_GetITFlag(TMR0_3_IT_CYC_END)) {
        TMR0_ClearITFlag(TMR0_3_IT_CYC_END);  // 清除中断标志
        mo_tick_inc();
        // GPIOB_InverseBits(GPIO_Pin_15);
    }
}
#endif

/*********************************************************************
 * @fn      mo_1ms_timer_nit
 *
 * @brief   Initializes Systick.
 *
 * @return  none
 */
/*@TODO need to init a 1mS timer for mcu os tick*/
void mo_1ms_timer_nit(void) {
#ifdef MO_CHV32V30x
    SysTick->SR = 0;
    SysTick->CNT = 0;
    SysTick->CMP = SystemCoreClock / 8 / 1000;
    SysTick->CTLR = 0x3;
    Interrupt_VTF_Init();
#endif

#ifdef MO_CH58x
    TMR0_TimerInit(FREQ_SYS / 1000);        // 设置定时时间 1ms
    TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END);  // 开启中断
    PFIC_EnableIRQ(TMR0_IRQn);
#endif
}

#ifdef WINDOWS_DEMO_EN
void CALLBACK mo_tick_timer_irq_handle(HWND t, UINT s, UINT_PTR w, DWORD d) {
    // printf("timer callback \n");
    mo_tick_inc();
}

/*******************************Windows thread*******************************/
DWORD dwtimerID = 0;

DWORD CALLBACK thread(PVOID pvoid) {
    MSG msg;

    dwtimerID = SetTimer(NULL, 1, 1, mo_tick_timer_irq_handle);

    while (GetMessage(&msg, NULL, 0, 0)) {
        if (msg.message == WM_TIMER) {
            // printf("i get a word: \n");
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    KillTimer(NULL, dwtimerID);

    return 0;
}
/****************************************************************************/

void mo_1ms_timer_nit(void) { /*for 1ms systick timer*/

    /*@TODO: here to init your own MCU timer as 1mS***/
    DWORD dwThreadId = 0;
    HANDLE hthread = CreateThread(NULL, 0, thread, 0, 0, &dwThreadId);
}

#endif

mo_u32 mo_get_tick(void) { return mo_tick; }

/**************
return val: TRUE indecats that the global interrupt is enabled
                   FALSE indecats that it is disabled
**************/
mo_u32 mo_get_global_int_state(void) {
    /**@TODO: Here to get the global interrupt status of the MCU you own****/
#ifdef OS_FOR_STM8
    /*for stm8**/
    mo_u8 ccr = 0;
    ccr = ITC_GetCPUCC();
    if ((ccr & 0x28) == 0x28) { /**means I1 and I0 are setted as 11(level 3)**/
        return 1;
    } else {
        return 0;
    }
#elif defined(MO_CH58x)
    mo_u32 ints = (PFIC->ISR[0] >> 8) | (PFIC->ISR[1] << 24);
    return ints;
#else
    return 0;
#endif
}

/**************
return ret: TRUE indecats that the global interrupt is enabled before
                   FALSE indecats that it is disabled before
**************/
mo_u32 mo_critical_enter(void) {
    mo_u32 ret;
    ret = mo_get_global_int_state();

    /**@TODO: here to disable the global interrupt of the MCU you own***/
#ifdef OS_FOR_STM8 /*for stm8**/
    disableInterrupts();
#elif defined(OS_FOR_STM32) /*for stm32f0xx*/
    __disable_irq();
#elif defined(MO_CH58x)     /*for MO_CH58x*/
    SYS_DisableAllIrq(&ret);
#endif

    return ret;
}

/**************
parameter prev_int_state: the previous int state that is returned by call
critical_enter() function
**************/
void mo_critical_exit(mo_u32 prev_int_state) {
    //	mo_u8 ret;
#ifdef MO_CH58x
    SYS_RecoverIrq(prev_int_state);
#else

    if (prev_int_state) {
        /**@TODO: here to enable the global interrupt of the MCU you own***/

#ifdef OS_FOR_STM8          /*for stm8**/
        enableInterrupts();
#elif defined(OS_FOR_STM32) /*for stm32f0xx*/
        __enable_irq();
#endif
  }
}


#if MO_DEBUG_EN
/*@TODO binding printf fun. here below*/
extern UART_HandleTypeDef huart2;
/*this is for Keil&IAR IDE*/

int fputc(int ch, FILE *f){
  HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
  return ch;
}

/*This is for other IDE such as: GCC*/
// int __io_putchar(int ch){
//   HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
//   return ch;
// }
#endif

#if 0 /*here below code is used to bind the uart to printf() function to 
        print log information via uart*/
        
#if MO_DEBUG_EN
#include "stdio.h"
//#include "Usart.h"
#ifdef OS_FOR_STM32
//#include "cmsis_gcc.h"
#include "stm32f072xb.h"
#endif

#pragma import(__use_no_semihosting)
/* 标准库需要的支持函数 */
struct __FILE {
  int handle;
};

FILE __stdout;
/* 定义_sys_exit()以避免使用半主机模式     */
void _sys_exit(int x) { x = x; }
/* 重定义fputc函数 */
int fputc(int ch, FILE *f) {
  /*Hear to provide the UART send data function
    for example as below is for stm32f072xb*/
  /* 选择USART1发送 */
  while ((USART1->ISR & 0X40) == 0);  // 循环发送,直到发送完毕
  USART1->TDR = (uint8_t)ch;
  
  return ch;
}
#endif
#endif 